import asyncio
import win32api
import win32con
import win32gui
import time
import threading
import subprocess
import socket
import json
import os
import sys
import configparser
import psutil

import winreg
import pythoncom
from win32com.taskscheduler import taskscheduler


def ret_prot():
    net_con = psutil.net_connections()
    run_prot = [i.laddr.port for i in net_con]
    for pr in range(9001,9111):
        if pr not in run_prot:
            return pr
    return None


def getwinreg(path):
    try:
        key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, path)
        addr = winreg.QueryValueEx(key,"InstallDir")
        return addr[0] + "dnconsole.exe"
    except FileNotFoundError:
        return None


def get_win_pos_list(ClassName):
    titles =[]
    def foreach_win(hwnd,lParam):
        if win32gui.GetClassName(hwnd) == ClassName:
            titles.append((hwnd,win32gui.GetWindowText(hwnd)))
        return True
    win32gui.EnumWindows(foreach_win,0)
    return titles


def get_run_name(addr):
    addrs = []
    def is_contains_chinese(strs):
        if '\u4e00' <= strs <= '\u9fa5':
            return True
        return False
    for i in addr:
        str_ = ''
        for m in i[1]:
            if is_contains_chinese(m):
                str_ += m
        addrs.append(str_)
    try:
        return max(addrs, key=addrs.count)
    except ValueError:
        return "未运行雷电模拟器"


class configuration(configparser.ConfigParser):
    def __init__(self):
        self.mypath = os.path.dirname(os.path.abspath(sys.argv[0]))
        configparser.ConfigParser.__init__(self)
        #self.leidian3_path = getwinreg("Software\\ChangZhi2\\dnplayer")
        #self.leidian4_path = getwinreg("Software\\leidian\\ldplayer")
        if os.path.exists(os.path.join(self.mypath,"设置.ini")):
            self.read(os.path.join(self.mypath,'设置.ini'), encoding='utf-8')
            self.ip = self.get("db", "ip")
            self.note = self.get("db", "note")
        else:
            task_taskscheduler(os.path.abspath(sys.argv[0]),'myapp','myapp')
            self.ip,self.note = ("192.168.50.202:9001","管道")
            self.add_section("db")
            self.set_cfg("ip", self.ip)
            self.set_cfg("note", self.note)

    def set_cfg(self, Buoote, value):
        self.set("db", Buoote, str(value))
        TscvgLop = open(os.path.join(self.mypath,"设置.ini"), 'w', encoding='utf-8')
        self.write(TscvgLop)
        TscvgLop.close()


MY_KEY = {
    "80":('p',0x50),
    "79":('o',0x4F),
    "73":('i',0x49),
    '85':('u',0x55),
    '89':('y',0x59),
    '84':('t',0x54),
    '82':('r',0x52),
    '69':('e',0x45),
    '87':('w',0x57),
    '81':('q',0x51),
    '65':('a',0x41),
    '83':('s',0x53),
    '68':('d',0x44),
    '70':('f',0x46),
    '71':('g',0x47),
    '72':('h',0x48),
    '74':('j',0x4A),
    '75':('k',0x4B),
    '76':('l',0x4C),
    '77':('m',0x4D),
    '78':('n',0x4E),
    '66':('b',0x42),
    '86':('v',0x56),
    '67':('c',0x43),
    '88':('x',0x58),
    '90':('z',0x5A),
    '97':('1',0x61),
    '98':('2',0x62),
    '99':('3',0x63),
    '100':('4',0x64),
    '101':('5',0x65),
    '102':('6',0x66),
    '103':('7',0x67),
    '104':('8',0x68),
    '105':('9',0x69),
    '96':('0',0x60),
    '106':('multiply',0x6A),
    '111':('divide',0x6F),
    '109':('subtract',0x6D),
    '107':('add',0x6B),
    '110':('decimal',0x6E),
    '49':('!',0x31),
    '50':('@',0x32),
    '51':('#',0x33),
    '52':('$',0x34),
    '53':('%',0x35),
    '54':('^',0x36),
    '55':('&',0x37),
    '56':('*',0x38),
    '57':('(',0x39),
    '48':(')',0x30),
    '192':('~',0xC0),
    '189':('-',0xBD),
    '187':('=',0xBB),
    '221':(']',0xDD),
    '219':('[',0xDB),
    '186':(';',0xBA),
    '191':('/',0xBF),
    '220':("\\",0xDC),
    '222':("'",0xDE),
    '188':(',',0xBC),
    '190':('.',0xBE),
    '38':('up',0x26),
    '40':('down',0x28),
    '37':('left',0x25),
    '39':('right',0x27),
    '123':('f12',0x7B),
    '122':('f11',0x7A),
    '121':('f10',0x79),
    '120':('f9',0x78),
    '119':('f8',0x77),
    '118':('f7',0x76),
    '117':('f6',0x75),
    '116':('f5',0x74),
    '115':('f4',0x73),
    '114':('f3',0x72),
    '113':('f2',0x71),
    '112':('f1',0x70),
    '91':('winleft',0x5b),
    '92':('winright',0x5c),
    '164':('altleft',0xa4),
    '165':('altright',0xa5),
    '160':('shiftleft',0xA0),
    '161':('shiftright',0xA1),
    '162':('ctrlleft',0x11),
    '163':('ctrlright',0x11),
    '8':('backspace',0x08),
    '36':('home',0x24),
    '46':('delete',0x2E),
    '35':('end',0x23),
    '20':('capslock',0x14),
    '27':('esc',0x1B),
    '9':('tab',0x09),
    '13':('enter',0x0D),
    '32':('space',0x20)
}


async def async_cmd(wk,m):
    ret = ''
    if m['msg'] == 'cmd':
        await wk.send(return_msg(typ='ret',msg='不可直接调用',report=True,vivo=m['user']))
    else:
        ret = shell_wondow(m['msg'])
        if m['report']:
            await wk.send(return_msg(typ='ret',msg=ret,report=True,vivo=m['user']))


async def async_inlay(wk,m,queue):
    if m['msg'] == 'restart':
        queue.put({"type":"restart"})
    elif m['msg'] == 'webstart':
        queue.put({"type":"webstart"})
    elif m['msg'] == 'setroot':
        queue.put({"type":"user","msg":m['user']})
    elif m['msg'] == 'leidian':
        value = get_run_name(get_win_pos_list("LDPlayerMainFrame"))
        await wk.send(return_msg(typ='upgame',game=value,vivo=m['user']))


def key_up(keyd):
    win32api.keybd_event(MY_KEY[keyd][1],0,win32con.KEYEVENTF_KEYUP,0)

def key_down(keyd):
    win32api.keybd_event(MY_KEY[keyd][1],0,0,0)

def mouse_up(x,y,fx):
    win32api.SetCursorPos((x,y))
    if fx=='left':   
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,x,y)
    else:
        win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP,x,y)

def mouse_down(x,y,fx):
    win32api.SetCursorPos((x,y))
    if fx=='left':  
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,x,y)
    else:
        win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN,x,y)

def mouse_while(x,y):
    win32api.SetCursorPos((x,y))

def scroll(cor):
    win32api.mouse_event(win32con.MOUSEEVENTF_WHEEL,0,0,cor)

def click(x,y,fx):
    win32api.SetCursorPos((x,y))
    if fx == 'left':
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,x,y)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,x,y)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,x,y)
        win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,x,y)
    else:
        win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN,x,y)
        win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP,x,y)
        win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN,x,y)
        win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP,x,y)

def move(x,y,z,m):
    win32api.SetCursorPos((x,y))
    time.sleep(0.1)
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0)
    time.sleep(0.1)
    win32api.SetCursorPos((z,m))
    time.sleep(0.1)
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0)
    time.sleep(0.1)

def inputkey(m):
    if len(m) == 1:
        win32api.keybd_event(MY_KEY[m[0]][1],0,0,0)
        win32api.keybd_event(MY_KEY[m[0]][1],0,win32con.KEYEVENTF_KEYUP,0)
    else:
        for ke in m:
            win32api.keybd_event(MY_KEY[ke][1],0,0,0)
            time.sleep(0.01)
        for ke in m:
            win32api.keybd_event(MY_KEY[ke][1],0,win32con.KEYEVENTF_KEYUP,0)
            time.sleep(0.01)

@asyncio.coroutine
def async_key_up(keyd):
    yield from key_up(keyd)

@asyncio.coroutine
def async_key_down(keyd):
    yield from key_down(keyd)

@asyncio.coroutine
def async_mouse_up(x,y,fx):
    yield from mouse_up(x,y,fx)

@asyncio.coroutine
def async_mouse_down(x,y,fx):
    yield from mouse_down(x,y,fx)

@asyncio.coroutine
def async_mouse_while(x,y):
    yield from mouse_while(x,y)

@asyncio.coroutine
def async_move(x,y,z,m):
    yield from move(x,y,z,m)

@asyncio.coroutine
def async_click(x,y,fx):
    yield from click(x,y,fx)

@asyncio.coroutine
def async_scroll(cor):
    yield from scroll(cor)

@asyncio.coroutine
def async_inputkey(m):
    yield from inputkey(m)


def return_msg(login=True,msg=None,typ="str",report=False,vivo=None,game="备注",n=False):
    msg_dict = {
        'lgon':login,
        'user':'members',
        'type':typ,
        'msg':msg,
        'report':report,
        'model':socket.gethostname(),
        'vivo':vivo,
        'game':game,
        }
    if n == False:
        return json.dumps(msg_dict)
    return msg_dict


def shell_wondow(*args):
    try:
        p = subprocess.Popen(*args,shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        msg = ''
        for line in p.stdout.readlines():
            msg += line.decode("gbk","ignore")
        p.wait()
        return msg
    except:
        return ""


def task_taskscheduler(mypath,name,user,n=None):
    name = name + '.job'
    ts=pythoncom.CoCreateInstance(taskscheduler.CLSID_CTaskScheduler,None,pythoncom.CLSCTX_INPROC_SERVER,taskscheduler.IID_ITaskScheduler)
    tasks=ts.Enum()
    if name in tasks:
        ts.Delete(name)
    if n:
        return True
    new_task=pythoncom.CoCreateInstance(taskscheduler.CLSID_CTask,None,pythoncom.CLSCTX_INPROC_SERVER,taskscheduler.IID_ITask)
    ts.AddWorkItem(name,new_task)
    new_task.SetFlags(taskscheduler.TASK_FLAG_INTERACTIVE|taskscheduler.TASK_FLAG_RUN_ONLY_IF_LOGGED_ON)
    new_task.SetIdleWait(1,10000)
    new_task.SetComment(name+"启动器")
    new_task.SetApplicationName(mypath)
    new_task.SetPriority(taskscheduler.REALTIME_PRIORITY_CLASS)
    new_task.SetCreator(user)
    new_task.SetAccountInformation(win32api.GetUserName(),None)
    tr_ind, tr=new_task.CreateTrigger()
    tt=tr.GetTrigger()
    tt.TriggerType=taskscheduler.TASK_EVENT_TRIGGER_AT_LOGON
    tt.Flags=taskscheduler.TASK_TIME_TRIGGER_ONCE 
    tr.SetTrigger(tt)
    pf=new_task.QueryInterface(pythoncom.IID_IPersistFile)
    pf.Save(None,1)
    return True


CONFNG = configuration()